package com.vogue.supplymall.order.domain.biz.impl;

import com.vogue.supplymall.account.domain.model.BaseCode;
import com.vogue.supplymall.account.domain.service.BaseCodeService;
import com.vogue.supplymall.common.domain.dto.UpdatePrepay;
import com.vogue.supplymall.common.exception.DataNotFindException;
import com.vogue.supplymall.match.domain.model.MatchOrgan;
import com.vogue.supplymall.match.domain.service.MatchOrganService;
import com.vogue.supplymall.order.domain.biz.PrepayBiz;
import com.vogue.supplymall.order.domain.model.Account;
import com.vogue.supplymall.order.domain.model.AccountPrepay;
import com.vogue.supplymall.order.domain.model.AccountPrepayDetail;
import com.vogue.supplymall.order.domain.service.AccountPrepayDetailService;
import com.vogue.supplymall.order.domain.service.AccountPrepayService;
import com.vogue.supplymall.order.domain.service.AccountService;
import com.vogue.supplymall.order.exception.AddPrepayException;
import com.vogue.supplymall.order.exception.DuplicationPrepayException;
import com.vogue.supplymall.order.exception.UpdatePrepayException;
import org.apache.commons.beanutils.BeanUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.lang.reflect.InvocationTargetException;
import java.math.BigDecimal;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * The type Prepay biz.
 *
 * @author zhangliang
 * Create in 2018-08-23
 */
@Service("prepayBiz")
public class PrepayBizImpl implements PrepayBiz {
    /**
     * The constant LOGGER_PREPAYBIZIMPL.
     */
    public static final Logger LOGGER_PREPAYBIZIMPL = LoggerFactory.getLogger(PrepayBizImpl.class);
    @Resource
    private AccountService accountService;
    @Resource
    private AccountPrepayService accountPrepayService;
    @Resource
    private AccountPrepayDetailService accountPrepayDetailService;
    @Resource
    private BaseCodeService baseCodeService;
    @Resource
    private MatchOrganService matchOrganService;

    @Override
    public void createPrepayForCld(UpdatePrepay updatePrepay) {
        // 获取买卖家的syscodeid
        Map<String, Object> basePara = new HashMap<>();
        basePara.put("sellsyscode", updatePrepay.getSellSyscode());
        basePara.put("buysyscode", updatePrepay.getBuySyscode());
        BaseCode sellCode = baseCodeService.selectOneByWhr0("syscode = #{sellsyscode}", basePara);
        BaseCode buyCode = baseCodeService.selectOneByWhr0("syscode = #{buysyscode}", basePara);
        if (null == sellCode) {
            throw new DataNotFindException("卖家");
        }
        if (null == buyCode) {
            throw new DataNotFindException("买家");
        }
        String accountSql = " syscodeid = #{syscodeid} and matchid = #{matchid} ";
        Map<String, Object> para = new HashMap<>();
        para.put("syscodeid", buyCode.getId());
        para.put("matchid", updatePrepay.getBuymatchid());
        // 新建账户
        newPrepay(accountSql, para, updatePrepay, buyCode, sellCode);
        LOGGER_PREPAYBIZIMPL.info("云供应链创建预付货款账户处理完成！买家syscode={}，卖家syscode={}，金额={}", updatePrepay.getBuySyscode(), updatePrepay.getSellSyscode(), updatePrepay.getAmount());
    }

    @Override
    @Transactional
    public void updatePrepayForCld(UpdatePrepay updatePrepay) {
        // 获取买卖家的syscodeid
        Map<String, Object> basePara = new HashMap<>();
        basePara.put("sellsyscode", updatePrepay.getSellSyscode());
        basePara.put("buysyscode", updatePrepay.getBuySyscode());
        BaseCode sellCode = baseCodeService.selectOneByWhr0("syscode = #{sellsyscode}", basePara);
        BaseCode buyCode = baseCodeService.selectOneByWhr0("syscode = #{buysyscode}", basePara);
        if (null == sellCode) {
            throw new DataNotFindException("卖家");
        }
        if (null == buyCode) {
            throw new DataNotFindException("买家");
        }
        String accountSql = " syscodeid = #{syscodeid} and matchid = #{matchid} ";
        Map<String, Object> para = new HashMap<>();
        para.put("syscodeid", buyCode.getId());
        para.put("matchid", updatePrepay.getBuymatchid());
        Account account = accountService.selectOneByWhr0(accountSql, para);
        // 如果没有账户就创建账户
        if (null == account) {
            newPrepay(accountSql, para, updatePrepay, buyCode, sellCode);
        } else {
            // 如果账户存在，并且为更新操作，就更新账户信息
            String prepaySql = " accountid = #{accountid} and sellsyscodeid = #{sellsyscodeid} and "
                    + "sellmatchid = #{sellmatchid} and buysyscodeid = #{buysyscodeid} and buymatchid = #{buymatchid}";
            para.put("accountid", account.getId());
            para.put("arapbillid", updatePrepay.getArapbillid());
            para.put("serialnum", updatePrepay.getSerialNum());
            para.put("sellsyscodeid", sellCode.getId());
            para.put("sellmatchid", updatePrepay.getSellmatchid());
            para.put("buysyscodeid", buyCode.getId());
            para.put("buymatchid", updatePrepay.getBuymatchid());

            AccountPrepay accountPrepay = accountPrepayService.selectOneByWhr0(prepaySql, para);
            if (null == accountPrepay) {
                para.put("syscodeid", buyCode.getId());
                para.put("matchid", updatePrepay.getBuymatchid());
                MatchOrgan buyMatchOrgan = matchOrganService.selectOneByWhr0(accountSql, para);
                if (null == buyMatchOrgan) {
                    throw new DataNotFindException("买家企业的信息");
                }
                para.put("syscodeid", sellCode.getId());
                para.put("matchid", updatePrepay.getSellmatchid());
                MatchOrgan sellMatchOrgan = matchOrganService.selectOneByWhr0(accountSql, para);
                if (null == sellMatchOrgan) {
                    throw new DataNotFindException("卖家企业的信息");
                }

                accountPrepay = new AccountPrepay();
                accountPrepay.setAccountid(account.getId());
                accountPrepay.setSellorganid(sellMatchOrgan.getId());
                accountPrepay.setSellsyscodeid(sellCode.getId());
                accountPrepay.setSellmatchid(updatePrepay.getSellmatchid());
                accountPrepay.setBuyorganid(buyMatchOrgan.getId());
                accountPrepay.setBuysyscodeid(buyCode.getId());
                accountPrepay.setBuymatchid(updatePrepay.getBuymatchid());
                accountPrepay.setBalance(BigDecimal.ZERO);
                // 消费:1 减少余额，其他情况增加余额
                switch (updatePrepay.getType()) {
                    case 1:
                        accountPrepay.setBalance(accountPrepay.getBalance().subtract(updatePrepay.getAmount()));
                    case 5:
                        accountPrepay.setBalance(accountPrepay.getBalance().subtract(updatePrepay.getAmount()));
                        break;
                    default:
                        accountPrepay.setBalance(accountPrepay.getBalance().add(updatePrepay.getAmount()));
                }
                // 余额不足返回msg
                if (accountPrepay.getBalance().compareTo(BigDecimal.ZERO) < 0) {
                    throw new UpdatePrepayException("余额不足！");
                }
                accountPrepayService.save(accountPrepay);
                LOGGER_PREPAYBIZIMPL.info("新建买家账户余额 syscode={}，余额={}", updatePrepay.getBuySyscode(), updatePrepay.getAmount());
            } else {
                // 消费:1 减少余额，其他情况增加余额
                switch (updatePrepay.getType()) {
                    case 1:
                        accountPrepay.setBalance(accountPrepay.getBalance().subtract(updatePrepay.getAmount()));
                        break;
                    case 5:
                        accountPrepay.setBalance(accountPrepay.getBalance().subtract(updatePrepay.getAmount()));
                        break;
                    default:
                        accountPrepay.setBalance(accountPrepay.getBalance().add(updatePrepay.getAmount()));
                        break;
                }
                // 余额不足返回msg
                if (accountPrepay.getBalance().compareTo(BigDecimal.ZERO) < 0) {
                    throw new UpdatePrepayException("余额不足！");
                }
                accountPrepay.setModifyDate(new Date());
                accountPrepayService.update(accountPrepay);
                LOGGER_PREPAYBIZIMPL.info("更新买家账户余额 syscode={}，余额={}", updatePrepay.getBuySyscode(), updatePrepay.getAmount());
            }
            if (updatePrepay.getAmount().compareTo(BigDecimal.ZERO) > 0) {
                AccountPrepayDetail prepayDetail = new AccountPrepayDetail();
                prepayDetail.setOrderid(0L);
                prepayDetail.setOrigin(1);
                prepayDetail.setType(updatePrepay.getType());
                prepayDetail.setAmount(updatePrepay.getAmount());
                prepayDetail.setAccountid(account.getId());
                prepayDetail.setArapbillid(updatePrepay.getArapbillid());
                prepayDetail.setBuymatchid(accountPrepay.getBuymatchid());
                prepayDetail.setBuyorganid(accountPrepay.getBuyorganid());
                prepayDetail.setBuysyscodeid(accountPrepay.getBuysyscodeid());
                prepayDetail.setSellmatchid(accountPrepay.getSellmatchid());
                prepayDetail.setSellorganid(accountPrepay.getSellorganid());
                prepayDetail.setSellsyscodeid(accountPrepay.getSellsyscodeid());
                prepayDetail.setRefundid(0L);
                prepayDetail.setSerialnum(updatePrepay.getSerialNum());
                if (StringUtils.isEmpty(updatePrepay.getMemo())) {
                    prepayDetail.setMemo("");
                } else {
                    prepayDetail.setMemo(updatePrepay.getMemo());
                }
                accountPrepayDetailService.save(prepayDetail);
                LOGGER_PREPAYBIZIMPL.info("新建买家账户余额明细 买家syscode={}，余额={}，类型={}", updatePrepay.getBuySyscode(), updatePrepay.getAmount(), updatePrepay.getType());
            }
            List<AccountPrepayDetail> prepayDetails = accountPrepayDetailService
                    .selectByWhr0(prepaySql + " and arapbillid = #{arapbillid} and serialnum = #{serialnum}", para);
            if (prepayDetails.size() > 2) {
                throw new DuplicationPrepayException("");
            }
            if (prepayDetails.size() == 2) {
                if (prepayDetails.get(0).getType() == prepayDetails.get(1).getType()) {
                    throw new DuplicationPrepayException("");
                }
            }
        }
        LOGGER_PREPAYBIZIMPL.info("云供应链更新预付货款处理完成！买家syscode={}，卖家syscode={}，金额={}", updatePrepay.getBuySyscode(), updatePrepay.getSellSyscode(), updatePrepay.getAmount());
    }

    /**
     * 新建账户
     *
     * @param accountSql   查询SQL
     * @param para         查询参数
     * @param updatePrepay 前端参数
     * @param buyCode      买家
     * @param sellCode     卖家
     */
    private void newPrepay(String accountSql, Map<String, Object> para, UpdatePrepay updatePrepay, BaseCode buyCode, BaseCode sellCode) {
        MatchOrgan buyMatchOrgan = matchOrganService.selectOneByWhr0(accountSql, para);
        if (null == buyMatchOrgan) {
            throw new DataNotFindException("新建账户-买家企业的信息");
        }
        Account account = accountService.selectOneByWhr0(accountSql, para);
        // 如果没有主账户就创建账户
        if (null == account) {
            account = new Account();
            account.setMatchid(updatePrepay.getBuymatchid());
            account.setSyscodeid(buyCode.getId());
            account.setOrganid(buyMatchOrgan.getId());
            accountService.save(account);
            LOGGER_PREPAYBIZIMPL.info("新建买家账户 syscode={}", updatePrepay.getBuySyscode());
        } else {
            LOGGER_PREPAYBIZIMPL.info("买家账户已存在 syscode={}", updatePrepay.getBuySyscode());
        }
        para.put("syscodeid", sellCode.getId());
        para.put("matchid", updatePrepay.getSellmatchid());
        MatchOrgan sellMatchOrgan = matchOrganService.selectOneByWhr0(accountSql, para);
        if (null == sellMatchOrgan) {
            throw new DataNotFindException("新建账户-卖家企业的信息");
        }

        String sql = " buyorganid = #{buyorganid} and buysyscodeid = #{buysyscodeid} "
                + "and sellsyscodeid = #{sellsyscodeid} and sellorganid = #{sellorganid}";
        Map<String, Object> paraPrepay = new HashMap<>();
        para.put("buyorganid", buyMatchOrgan.getId());
        para.put("buysyscodeid", buyCode.getId());
        para.put("sellsyscodeid", sellCode.getId());
        para.put("sellorganid", sellMatchOrgan.getId());
        AccountPrepay accountPrepay = accountPrepayService.selectOneByWhr0(sql, paraPrepay);
        if (accountPrepay == null) {
            accountPrepay = new AccountPrepay();
            accountPrepay.setAccountid(account.getId());
            accountPrepay.setBuymatchid(updatePrepay.getBuymatchid());
            accountPrepay.setBuysyscodeid(buyCode.getId());
            accountPrepay.setBuyorganid(buyMatchOrgan.getId());
            accountPrepay.setSellmatchid(updatePrepay.getSellmatchid());
            accountPrepay.setSellsyscodeid(sellCode.getId());
            accountPrepay.setSellorganid(sellMatchOrgan.getId());
            accountPrepay.setBalance(updatePrepay.getAmount());
            accountPrepayService.save(accountPrepay);
            LOGGER_PREPAYBIZIMPL.info("新建买家账户余额 syscode={}，余额={}", updatePrepay.getBuySyscode(), updatePrepay.getAmount());
        } else {
            LOGGER_PREPAYBIZIMPL.info("买卖家账户关系已存在 syscode={}，余额={}", updatePrepay.getBuySyscode(), updatePrepay.getAmount());
        }

        if (updatePrepay.getAmount().compareTo(BigDecimal.ZERO) > 0) {
            AccountPrepayDetail prepayDetail = new AccountPrepayDetail();
            prepayDetail.setOrderid(0L);
            prepayDetail.setOrigin(1);
            prepayDetail.setType(updatePrepay.getType());
            prepayDetail.setAmount(updatePrepay.getAmount());
            prepayDetail.setAccountid(account.getId());
            prepayDetail.setArapbillid(updatePrepay.getArapbillid());
            prepayDetail.setBuymatchid(accountPrepay.getBuymatchid());
            prepayDetail.setBuyorganid(accountPrepay.getBuyorganid());
            prepayDetail.setBuysyscodeid(accountPrepay.getBuysyscodeid());
            prepayDetail.setSellmatchid(accountPrepay.getSellmatchid());
            prepayDetail.setSellorganid(accountPrepay.getSellorganid());
            prepayDetail.setSellsyscodeid(accountPrepay.getSellsyscodeid());
            prepayDetail.setSerialnum(updatePrepay.getSerialNum());
            prepayDetail.setRefundid(0L);
            if (StringUtils.isEmpty(updatePrepay.getMemo())) {
                prepayDetail.setMemo("");
            } else {
                prepayDetail.setMemo(updatePrepay.getMemo());
            }
            accountPrepayDetailService.save(prepayDetail);
            LOGGER_PREPAYBIZIMPL.info("新建买家账户余额吗明细 syscode={}，余额={}，类型={}", updatePrepay.getBuySyscode(), updatePrepay.getAmount(), updatePrepay.getType());
        }
    }

    @Override
    @Transactional
    public void updatePrepay(UpdatePrepay updatePrepay) {
        String sql = " buyorganid = #{buyorganid} and buysyscodeid = #{buysyscodeid} "
                + "and sellsyscodeid = #{sellsyscodeid} and sellorganid = #{sellorganid}";
        Map<String, Object> para = new HashMap<>();
        para.put("buyorganid", updatePrepay.getBuyorganid());
        para.put("buysyscodeid", updatePrepay.getBuysyscodeid());
        para.put("sellsyscodeid", updatePrepay.getSellsyscodeid());
        para.put("sellorganid", updatePrepay.getSellorganid());
        AccountPrepay account = accountPrepayService.selectOneByWhr0(sql, para);
        if (null == account) {
            throw new AddPrepayException("找不到用户的账户");
        }
        if (updatePrepay.getType() == 3) {
            account.setBalance(account.getBalance().add(updatePrepay.getAmount()));
        }

        // 消费:1 减少余额，其他情况增加余额
        switch (updatePrepay.getType()) {
            case 1:
                account.setBalance(account.getBalance().subtract(updatePrepay.getAmount()));
                break;
            case 5:
                account.setBalance(account.getBalance().subtract(updatePrepay.getAmount()));
                break;
            default:
                account.setBalance(account.getBalance().add(updatePrepay.getAmount()));
                break;
        }
        account.setModifyDate(new Date());
        accountPrepayService.update(account);
        LOGGER_PREPAYBIZIMPL.info("更新账户余额：账户 {}", updatePrepay.getAccountid());
        if (updatePrepay.getAmount().compareTo(BigDecimal.ZERO) > 0) {
            AccountPrepayDetail accountPrepayDetail = new AccountPrepayDetail();
            try {
                BeanUtils.copyProperties(accountPrepayDetail, account);
            } catch (IllegalAccessException e) {
                e.printStackTrace();
                LOGGER_PREPAYBIZIMPL.error("bean copy error");
                throw new AddPrepayException("bean copy error");
            } catch (InvocationTargetException e) {
                e.printStackTrace();
                LOGGER_PREPAYBIZIMPL.error("bean copy error");
                throw new AddPrepayException("bean copy error");
            }
            accountPrepayDetail.setId(null);
            accountPrepayDetail.setAmount(updatePrepay.getAmount());
            accountPrepayDetail.setType(updatePrepay.getType());
            accountPrepayDetail.setOrigin(updatePrepay.getOrigin());
            if (StringUtils.isEmpty(updatePrepay.getMemo())) {
                accountPrepayDetail.setMemo("");
            } else {
                accountPrepayDetail.setMemo(updatePrepay.getMemo());
            }
            accountPrepayDetail.setOrderid(updatePrepay.getOrderid());
            if (null != updatePrepay.getRefundid()) {
                accountPrepayDetail.setRefundid(updatePrepay.getRefundid());
            } else {
                accountPrepayDetail.setRefundid(0L);
            }
            accountPrepayDetail.setCreateDate(new Date());
            accountPrepayDetail.setModifyDate(new Date());
            accountPrepayDetailService.save(accountPrepayDetail);
            LOGGER_PREPAYBIZIMPL.info("添加账户消费明细：账户：{}，金额：{}", updatePrepay.getAccountid(), updatePrepay.getAmount());
        }
    }

}
